# routes.py
from fastapi import APIRouter, HTTPException, Depends
from sqlalchemy.orm import Session
from pydantic import BaseModel
from passlib.context import CryptContext
from models import User, Product, Cart, Order, OrderItem
from database import get_db
from typing import Union
import re
router = APIRouter()

class CustomException(Exception):
    def __init__(self, code: int, msg: str):
        self.code = code
        self.msg = msg

class ResponseModel(BaseModel):
    code: int
    msg: str
    data: Union[dict, list, None]

class UserCreate(BaseModel):
    username: str
    password: str
    email: str

class ProductCreate(BaseModel):
    name: str
    price: float
    stock: int
    description: str = None

class CartItem(BaseModel):
    user_id: int
    product_id: int
    quantity: int

class OrderCreate(BaseModel):
    user_id: int
    cart_items: list[CartItem]


# 用户名校验：
# 长度限制：用户名长度一般在 6 到 20 个字符之间。
# 允许字符：可以包含字母、数字、下划线，但不能以数字开头。
# 不允许使用敏感词。

# 密码校验：
# 长度限制：密码长度一般在 8 到 20 个字符之间。
# 必须包含至少一个数字、一个字母和一个特殊字符（如 @、#、$、% 等）。
# 不建议使用容易被猜测的密码，比如连续字符或者简单的个人信息。

# 邮箱校验：
# 使用正则表达式来验证邮箱格式。

# 用户名校验
def validate_username(username: str) -> None:
    if len(username) < 6 or len(username) > 20:
        raise CustomException(code=400, msg="用户名长度必须在 6 到 20 个字符之间。")
    if not re.match("^[a-zA-Z_][a-zA-Z0-9_]*$", username):
        raise CustomException(code=400, msg="用户名只能包含字母、数字和下划线，且不能以数字开头。")

# 密码校验
def validate_password(password: str) -> None:
    if len(password) < 8 or len(password) > 20:
        raise CustomException(code=400, msg="密码长度必须在 8 到 20 个字符之间。")
    if not re.search(r"[A-Za-z]", password):
        raise CustomException(code=400, msg="密码必须至少包含一个字母。")
    if not re.search(r"[0-9]", password):
        raise CustomException(code=400, msg="密码必须至少包含一个数字。")
    if not re.search(r"[!@#$%^&*(),.?\":{}|<>]", password):
        raise CustomException(code=400, msg="密码必须至少包含一个特殊字符。")

# 邮箱校验
def validate_email(email: str) -> None:
    email_regex = r"^[\w\.-]+@[\w\.-]+\.\w+$"  # 简单的邮箱正则
    if not re.match(email_regex, email):
        raise CustomException(code=400, msg="无效的电子邮件格式。")
# 初始化密码哈希上下文
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")


@router.post("/register", response_model=ResponseModel)
async def register_user(user: UserCreate, db: Session = Depends(get_db)):
    """
    用户注册接口

    - **username**: 用户名，唯一，不可为空
    - **password**: 密码，不可为空
    - **email**: 电子邮件，唯一，不可为空

    返回：
    - **code**: 状态码，200 表示成功
    - **msg**: 操作信息消息
    - **data**: 额外返回数据，默认为空字典
    """
    try:
        # 验证参数是否为空
        if not user.username:
            raise CustomException(code=400, msg="用户名不能为空。")
        if not user.email:
            raise CustomException(code=400, msg="电子邮件不能为空。")
        if not user.password:
            raise CustomException(code=400, msg="密码不能为空。")

        # 校验用户名、密码和电子邮件
        validate_username(user.username)
        validate_password(user.password)
        validate_email(user.email)

        # 检查用户名或电子邮件是否已存在
        existing_user = db.query(User).filter(
            (User.username == user.username) | (User.email == user.email)
        ).first()
        if existing_user:
            if existing_user.username == user.username:
                raise CustomException(code=400, msg="用户名已存在。")
            if existing_user.email == user.email:
                raise CustomException(code=400, msg="电子邮件已被注册。")

        # 创建新用户实例并设置密码
        hashed_password = pwd_context.hash(user.password)
        new_user = User(username=user.username, email=user.email, password=hashed_password)

        # 保存到数据库
        db.add(new_user)
        db.commit()
        db.refresh(new_user)  # 刷新以获取新用户 ID 等信息

        return ResponseModel(code=200, msg="用户创建成功", data={"id": new_user.id})

    except CustomException as e:
        raise e  # 直接抛出自定义异常
    except Exception as e:
        db.rollback()  # 回滚事务
        raise CustomException(code=500, msg=f"服务器内部错误: {str(e)}")



@router.post("/api/users/login", response_model=ResponseModel)
async def login_user(user: UserCreate, db: Session = Depends(get_db)):
    """
       用户登录接口

       - **username**: 用户名，不可为空
       - **password**: 密码，不可为空

       返回：
       - **code**: 状态码，200 表示成功
       - **msg**: 操作信息消息
       - **data**: 包含登录令牌的字典
       """
    db_user = db.query(User).filter(User.username == user.username).first()
    if db_user and db_user.check_password(user.password):
        return ResponseModel(code=200, msg="登录成功", data={"token": "fake-jwt-token"})
    raise HTTPException(status_code=401, detail="无效的凭证。")

@router.post("/api/products", response_model=ResponseModel)
async def add_product(product: ProductCreate, db: Session = Depends(get_db)):
    """
       添加产品接口

       - **name**: 产品名称，不可为空
       - **price**: 产品价格，不可为空
       - **stock**: 产品库存，不可为空
       - **description**: 产品描述，可为空

       返回：
       - **code**: 状态码，200 表示成功
       - **msg**: 操作信息消息
       - **data**: 额外返回数据，默认为空字典
       """
    new_product = Product(name=product.name, price=product.price, description=product.description, stock=product.stock)
    db.add(new_product)
    db.commit()
    return ResponseModel(code=200, msg="产品添加成功", data={})

@router.get("/api/products", response_model=ResponseModel)
async def get_products(db: Session = Depends(get_db)):
    """
       获取所有产品接口

       返回：
       - **code**: 状态码，200 表示成功
       - **msg**: 操作信息消息
       - **data**: 产品列表，每个产品包含 id、name、price、description 和 stock
       """
    products = db.query(Product).all()
    product_list = [{"id": p.id, "name": p.name, "price": p.price, "description": p.description, "stock": p.stock} for p in products]
    return ResponseModel(code=200, msg="获取成功", data=product_list)

@router.post("/api/cart", response_model=ResponseModel)
async def add_to_cart(item: CartItem, db: Session = Depends(get_db)):
    """
        将产品添加到购物车接口

        - **user_id**: 用户ID，不可为空
        - **product_id**: 产品ID，不可为空
        - **quantity**: 数量，不可为空

        返回：
        - **code**: 状态码，200 表示成功
        - **msg**: 操作信息消息
        - **data**: 额外返回数据，默认为空字典
        """
    new_cart_item = Cart(user_id=item.user_id, product_id=item.product_id, quantity=item.quantity)
    db.add(new_cart_item)
    db.commit()
    return ResponseModel(code=200, msg="产品已添加到购物车", data={})

@router.get("/api/cart", response_model=ResponseModel)
async def get_cart(user_id: int, db: Session = Depends(get_db)):
    """
        获取用户购物车中的产品接口

        - **user_id**: 用户ID，不可为空

        返回：
        - **code**: 状态码，200 表示成功
        - **msg**: 操作信息消息
        - **data**: 购物车项目列表，包括每个产品的 ID 和数量
        """
    cart_items = db.query(Cart).filter_by(user_id=user_id).all()
    item_list = [{"product_id": item.product_id, "quantity": item.quantity} for item in cart_items]
    return ResponseModel(code=200, msg="获取购物车成功", data=item_list)

@router.post("/api/orders", response_model=ResponseModel)
async def create_order(order: OrderCreate, db: Session = Depends(get_db)):
    """
       创建订单接口

       - **user_id**: 用户ID，不可为空
       - **cart_items**: 购物车项目列表，包含每个项目的 product_id 和数量

       返回：
       - **code**: 状态码，200 表示成功
       - **msg**: 操作信息消息
       - **data**: 额外返回数据，默认为空字典
       """
    total_price = 0
    for item in order.cart_items:
        product = db.query(Product).get(item.product_id)
        if product:
            total_price += product.price * item.quantity
    new_order = Order(user_id=order.user_id, total_amount=total_price, status='待支付')
    db.add(new_order)
    db.commit()
    for item in order.cart_items:
        order_item = OrderItem(order_id=new_order.id, product_id=item.product_id, quantity=item.quantity, price=product.price)
        db.add(order_item)
    db.commit()
    return ResponseModel(code=200, msg="订单创建成功", data={})

@router.get("/api/products/search", response_model=ResponseModel)
async def search_products(query: str, db: Session = Depends(get_db)):
    """
       搜索产品接口

       - **query**: 搜索关键字，产品名称中的一部分

       返回：
       - **code**: 状态码，200 表示成功
       - **msg**: 操作信息消息
       - **data**: 符合条件的产品列表，每个产品包含 ID、name 和 price
       """
    products = db.query(Product).filter(Product.name.like(f"%{query}%")).all()
    product_list = [{"id": p.id, "name": p.name, "price": p.price} for p in products]
    return ResponseModel(code=200, msg="搜索成功", data=product_list)
